﻿using System;
using System.Collections.Generic;
using System.Data;
using System.Dynamic;
using zijian666.SuperConvert.Core;
using zijian666.SuperConvert.Interface;

namespace zijian666.SuperConvert.Dynamic
{
    /// <summary>
    /// 基于 <seealso cref="DataRow" /> 的动态类型
    /// </summary>
    internal class DynamicDataRow : DynamicObjectBase<DataRow>
    {
        /// <summary>
        /// 初始化
        /// </summary>
        public DynamicDataRow(DataRow row, IConvertSettings convertSettings)
            : base(row, convertSettings)
        {
            if (row is null)
            {
                throw new ArgumentNullException(nameof(row));
            }
        }

        /// <summary>
        /// 初始化
        /// </summary>
        public DynamicDataRow(DataRowView row, ConvertSettings settings) : this(row?.Row, settings) { }


        public override IEnumerable<string> GetDynamicMemberNames()
        {
            foreach (DataColumn col in Value.Table.Columns)
            {
                yield return col.ColumnName;
            }
        }

        public override bool TryConvert(ConvertBinder binder, out object result)
        {
            if (typeof(IConvertible).IsAssignableFrom(binder.ReturnType))
            {
                var arr = Value.ItemArray;
                if ((arr.Length == 1) && TryChangeType(arr[0], binder.ReturnType, out result))
                {
                    return true;
                }
            }
            return TryChangeType(Value, binder.ReturnType, out result);
        }


        public override bool TryGetMember(GetMemberBinder binder, out object result)
        {
            result = Value[binder.Name];
            if (result != null)
            {
                if (TryChangeType(result, binder.ReturnType, out result))
                {
                    result = WrapToDynamic(result);
                    return true;
                }
            }

            result = DynamicPrimitive.Null;
            return true;
        }

        public override bool TrySetMember(SetMemberBinder binder, object value)
        {
            if (IsReadOnly)
            {
                return false;
                //throw new NotSupportedException("当前对象是只读的");
            }
            Value[binder.Name] = value.To<string>();
            return true;
        }

        private object Indexer(object[] indexes)
        {
            if ((indexes == null) || (indexes.Length != 1))
            {
                return null;
            }
            var index = indexes[0];
            if (index is string name)
            {
                if (Value.Table.Columns.Contains(name))
                {
                    return Value[name];
                }
                return null;
            }
            var i = index.Convert<int>(ConvertSettings).GetValueOrDefalut(-1);
            if ((i < 0) || (i > Value.ItemArray.Length))
            {
                return null;
            }
            return Value.ItemArray[i];
        }

        public override bool TryGetIndex(GetIndexBinder binder, object[] indexes, out object result)
        {
            result = Indexer(indexes);
            if (result != null)
            {
                if (TryChangeType(result, binder.ReturnType, out result))
                {
                    result = WrapToDynamic(result);
                    return true;
                }
            }

            result = DynamicPrimitive.Null;
            return true;
        }

        public override bool TrySetIndex(SetIndexBinder binder, object[] indexes, object value)
        {
            if (IsReadOnly)
            {
                return false;
            }

            if (indexes.Length != 1)
            {
                return false;
            }
            var index = indexes[0];
            if (index is string name)
            {
                if (Value.Table.Columns.Contains(name))
                {
                    var col = Value.Table.Columns[name];
                    if (TryChangeType(value, col.DataType, out value))
                    {
                        Value[col] = value;
                    }
                }
            }
            else
            {
                var i = index.To(-1);
                if ((i >= 0) && (i < Value.ItemArray.Length))
                {
                    var col = Value.Table.Columns[i];
                    if (TryChangeType(value, col.DataType, out value))
                    {
                        Value[col] = value;
                    }
                }
            }
            return false;
        }
    }
}
